package org.yihang.db;

import org.yihang.db.ColumnHandler.ColumnHandlers;

import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 处理javabean(实体类)格式的结果
 *
 * @author yihang
 */
public interface BeanHandler {

    /**
     * 存储各个Bean的处理器：key是bean的类型，value是处理器
     */
    ConcurrentHashMap<Class<?>, BeanHandler> BEAN_HANDLERS = new ConcurrentHashMap<>();

    /**
     * 将结果集({@link java.sql.ResultSet})中某一列的类型转换为java类型
     *
     * @param clazz bean的类型
     * @param rs    结果集
     * @return 转换后的bean实例对象
     * @throws SQLException 可能出现的jdbc异常
     */
    static Object process(Class<?> clazz, ResultSet rs) throws SQLException {
        BeanHandler handler = BEAN_HANDLERS.computeIfAbsent(clazz, c -> {
            final Map<String, PropertyDescriptor> propertyDescriptorMap;
            try {
                propertyDescriptorMap = Arrays.stream(Introspector.getBeanInfo(clazz).getPropertyDescriptors())
                        .collect(Collectors.toMap(p -> p.getName().toLowerCase(), p -> p));
            } catch (IntrospectionException e) {
                throw new RuntimeException(e);
            }
            return (BeanHandler) rs1 -> {
                try {
                    ResultSetMetaData rsmd = rs1.getMetaData();
                    Object beanInstance = clazz.newInstance();
                    for (int i = 1; i <= rsmd.getColumnCount(); i++) {
                        String colName = rsmd.getColumnLabel(i);
                        PropertyDescriptor pd = propertyDescriptorMap.get(colName.toLowerCase());
                        Object colValue = ColumnHandlers.process(pd.getPropertyType(), rs1, i);
                        pd.getWriteMethod().invoke(beanInstance, colValue);
                    }
                    return beanInstance;
                } catch (InstantiationException | InvocationTargetException | IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            };
        });
        return handler.toJava(rs);
    }

    /**
     * 将结果集({@link java.sql.ResultSet})中某一列的类型转换为java bean类型
     *
     * @param rs 结果集
     * @return 转换后的bean实例对象
     * @throws SQLException 可能出现的jdbc异常
     */
    Object toJava(ResultSet rs) throws SQLException;
}
